﻿using Furion.DatabaseAccessor;
using Furion.LinqBuilder;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq.Expressions;
using YFurion.Entities;
using YFurion.Extensions;

namespace YFurion.EntityFrameworkCore.MultiTenants
{
    public abstract class MultiTenantSlaveDbContext<TDbContext, TDbContextLocator> : ReadOnlyDbContext<TDbContext, TDbContextLocator>, IYMultiTenantOnDatabase, IYMultiTenantOnTable
        where TDbContext : DbContext
        where TDbContextLocator : class, IDbContextLocator
    {
        protected bool IsTenantFilterEnabled => DataFilter.HasFilter(nameof(IHasTenant.TenantId)) ? DataFilter.IsFilterEnabled(nameof(IHasTenant.TenantId)) : false;

        public MultiTenantSlaveDbContext(DbContextOptions<TDbContext> options) : base(options)
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            string connectionString = GetDatabaseConnectionString();
            if (!connectionString.IsNullOrWhiteSpace())
            {
                optionsBuilder.UseSqlServer(connectionString);
            }
            base.OnConfiguring(optionsBuilder);
        }

        public abstract string GetDatabaseConnectionString();

        protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
        {
            Expression<Func<TEntity, bool>> expression = base.CreateFilterExpression<TEntity>();
            if (typeof(IHasTenant).IsAssignableFrom(typeof(TEntity)))
            {
                Expression<Func<TEntity, bool>> tenantFilter = e => !IsTenantFilterEnabled || GetTenantId() == null || !(GetTenantId() is string) || (GetTenantId() as string) == string.Empty || ((IHasTenant)e).TenantId.Equals(GetTenantId().ToString());
                expression = expression == null ? tenantFilter : expression.And(tenantFilter);
            }
            return expression;
        }

        public virtual object GetTenantId()
        {
            return YSession.GetTenantId();
        }
    }
}